
#define OCEAN_DEG_TO_PI (0.017453) // 360/2*PI

vec3 GenerateWavesFromNoises(sampler2D iWatterTexture, vec2 iTexCoords, float iTime, float iS)
{
  float sinAngle, cosAngle;
  const int nbDirections = 1;
  float spread = OCEAN_DEG_TO_PI*iS;
  vec3 currentLayer = vec3(0.0,0.0,0.0);
    
  float uNormalize = 0.42;
  float uBumpStrength = 0.4;
    
  for (int i=0; i<cb_Ground_Ocean.u_NbDirection; i++)
  {
    float angle = spread * float(i)/float(nbDirections);
    cosAngle = vCos(angle);
    sinAngle = vSin(angle);
    vec2 diri =  vec2( cosAngle, sinAngle );
    vec2 UV = iTexCoords + iTime * diri;
    vec3 clt = vNormalize(vTexture(iWatterTexture, UV).rgb*vec3(2,2,1)-vec3(1,1,0));
    clt.xy *= uBumpStrength;
    currentLayer += vNormalize(clt);
  } 		
    
  currentLayer /= float(nbDirections);
  return currentLayer.xyz;
}

vec3 ComputeNormal()
{
  float timer = cb_Time.u_ElapsedTime;
  float waterSpeed = cb_Ground_Ocean.u_WaveSpeed*timer;

  vec2 textCoord = vLocalPosition.xy*(cb_Ground.u_GroundScaling.x/cb_Ground_Ocean.u_WaveScaling);

  vec3 pwave1 = GenerateWavesFromNoises(s_OceanNormalMapTexture0, 
    cb_Ground_Ocean.u_Wave0_ScaleRatio*textCoord,  
    cb_Ground_Ocean.u_Wave0_SpeedRatio*waterSpeed, 
    cb_Ground_Ocean.u_Wave0_Angle);
  vec3 pwave2 = GenerateWavesFromNoises(s_OceanNormalMapTexture1, 
    cb_Ground_Ocean.u_Wave1_ScaleRatio*textCoord,  
    cb_Ground_Ocean.u_Wave1_SpeedRatio*waterSpeed, 
    cb_Ground_Ocean.u_Wave1_Angle);   
  vec3 pwave3 = GenerateWavesFromNoises(s_OceanNormalMapTexture2, 
    cb_Ground_Ocean.u_Wave2_ScaleRatio*textCoord,  
    cb_Ground_Ocean.u_Wave2_SpeedRatio*waterSpeed, 
    cb_Ground_Ocean.u_Wave2_Angle);    
  vec3 pwave =  pwave1+pwave2+pwave3;

  vec4 n = vec4(pwave, 0);
  n = vNormalize(vGetViewInverseMatrix() * cb_Ground_Matrix.u_GroundMatrix * n);
  return n.xyz;
}

vec4 ComputeLighting(vec3 iWorldNormal)
{   
  vec3 viewDir = vNormalize(_vPrivGetWorldEyePos() - (vGetViewInverseMatrix() * vec4(vViewPosition.xyz, 1)).xyz);
 
  // Fresnel
  float uFresnel    = cb_Ground_Ocean.u_FresnelCoef;
  float basef       = 1.0-vAbs(vDot(viewDir, iWorldNormal));
  float expof       = vPow(basef, cb_Ground_Ocean.u_ExpCoef);
  float reflFresnel = uFresnel * 2.0 * (expof*0.4);
  
  vec3 diffuseIBLSample   = cb_Ground_Ocean.u_DiffuseColor;
  vec3 specularIBLSample  = cb_Ground_Ocean.u_SpecularColor;

  //IBL
#ifdef ImageBasedLighting
  
#ifdef ImageBasedLighting_Transfo
  vec3 N = (cb_IBL.u_IBLTransfoMatrix*vec4(iWorldNormal, 0.0)).xyz;
  vec3 V = (cb_IBL.u_IBLTransfoMatrix*vec4(viewDir, 0.0)).xyz;
#else
  vec3 N = iWorldNormal;
  vec3 V = viewDir;
#endif

  vec3 R = vNormalize(-vReflect(V, N));

  diffuseIBLSample  = vTextureCubeMap(IBLDiffuseTexture, R).rgb * cb_IBL.u_IBLDiffuseScaleFactor;
  specularIBLSample = vTextureCubeMapLod(IBLSpecularTexture, R, 0).rgb * cb_IBL.u_IBLSpecularScaleFactor;

#endif
      
#ifdef GROUND_MIRRORING
  vec4 mirrorCol = GetGroundMirrorColor(iWorldNormal);
  
  #ifdef ImageBasedLighting
  if (mirrorCol.w!=0)
  {
    // on prend la contribution sans le ciel qui est deja dans la map specualaire d'ibl
    specularIBLSample = vMix(specularIBLSample, mirrorCol.xyz, cb_Ground.u_MirrorCoef);
  }
  #else
  specularIBLSample = vMix(specularIBLSample, mirrorCol.xyz, cb_Ground.u_MirrorCoef);
  #endif
#endif

  vec3 contrib =  (reflFresnel+0.1) * specularIBLSample + diffuseIBLSample * vec3(0.09, 0.29, 0.56);
  contrib *= cb_Ground.u_GroundColor.xyz;
  
#if defined(GROUND_SHADOW) 
  contrib.xyz *= GetGroundShadowRatio();
#endif
  
#ifdef OutputIBLReflMap
  FRAGREFLECT.xyz = (reflFresnel+0.1) * specularIBLSample * cb_Ground.u_GroundColor.xyz;
  FRAGREFLECT.a = cb_Ground.u_GroundColor.w;
#endif
  
  return vec4(contrib, cb_Ground.u_GroundColor.w);
}
